// -----------------------------------------------------------------------------
// sys_chargen
// -----------------------------------------------------------------------------
/*
    Character generation script
*/
// -----------------------------------------------------------------------------
// owner: georg zoeller
// -----------------------------------------------------------------------------

/*

                int nSize = GetMaxInventorySize(oChar);
                LogTrace(LOG_CHANNEL_TEMP, "size = " + ToString(nSize));
                if (nSize == -1)
                {
                    SetMaxInventorySize(INVENTORY_SIZE_BASE, oChar);
                    nSize = GetMaxInventorySize(oChar);
                    LogTrace(LOG_CHANNEL_TEMP, "size = " + ToString(nSize));
                }
*/
#include "ascl_sys_chargen_h"
#include "log_h"
//#include "sys_autoscale_h"
#include "plt_gen00pt_backgrounds"
#include "ascl_sys_rewards_h"
#include "sys_autolevelup_h"
#include "achievement_core_h"

const int SCREEN_ENTER_DIRECTION_NEXT = 0;
const int SCREEN_ENTER_DIRECTION_BACK = 1;

const int CHARGEN_SCREEN_RACE_GENDER          = 0;
const int CHARGEN_SCREEN_CLASS_BACKGROUND     = 1;
const int CHARGEN_SCREEN_APPEARANCE_SOUNDSET  = 2;
const int CHARGEN_SCREEN_NAME                 = 3;
const int CHARGEN_SCREEN_ATTRIBUTES           = 4;
const int CHARGEN_SCREEN_SKILLS               = 5;
const int CHARGEN_SCREEN_TALENTS              = 6;
const int CHARGEN_SCREEN_SUMMARY              = 7;

const int INVENTORY_SIZE_BASE = 70;

const string UNINITIALIZED_NAME = "Jaden";

const int MAX_CLASS_INDEX = 3; // Last index of available base classes in cla_base.

const resource HERBALISM_STARTING_RECIPE1 = R"gen_im_cft_hrb_102.uti";
const resource HERBALISM_STARTING_RECIPE2 = R"gen_im_cft_hrb_206.uti";
const resource HERBALISM_STARTING_RECIPE3 = R"gen_im_cft_hrb_101.uti";
const resource POISON_MAKING_STARTING_RECIPE1 = R"gen_im_cft_psn_101.uti";
const resource POISON_MAKING_STARTING_RECIPE2 = R"gen_im_cft_psn_102.uti";
const resource TRAP_MAKING_STARTING_RECIPE1 = R"gen_im_cft_trp_104.uti";
const resource TRAP_MAKING_STARTING_RECIPE2 = R"gen_im_cft_trp_103.uti";
const resource TRAP_MAKING_STARTING_RECIPE3 = R"gen_im_cft_trp_205.uti";
const resource TRAP_MAKING_STARTING_RECIPE4 = R"gen_im_cft_trp_102.uti";
const resource RUNE_MAKING_STARTING_RECIPE1   = R"gen_im_cft_run_102.uti";     // upgrade flame
const resource RUNE_MAKING_STARTING_RECIPE2   = R"gen_im_cft_run_103.uti";     // upgrade frost
const resource RUNE_MAKING_STARTING_RECIPE3   = R"gen_im_cft_run_110.uti";     // upgrade storm
const resource RUNE_MAKING_STARTING_RECIPE4   = R"gen_im_cft_run_111.uti";     // upgrade sun

/*
 *  @brief Simulate a character levelup for test system
 *
 *  Simulates a character levelup for testing purposes
 *
 *  @param oChar The character
 *
 *  @author Georg Zoeller
*/
void _RunChargen(int nRace, int nClass, object oChar = OBJECT_SELF, int nBackground  = BACKGROUND_NOBLE )
{

    Chargen_InitializeCharacter(oChar);
    Chargen_SelectGender(oChar,GENDER_MALE);
    Chargen_SelectRace(oChar,nRace);
    Chargen_SelectCoreClass(oChar,nClass);
    Chargen_SelectBackground(oChar, nBackground,FALSE);

    int nEquipIdx = Chargen_GetEquipIndex(nRace, nClass, nBackground);
    Chargen_InitInventory(oChar,0,nEquipIdx);
    Chargen_SpendAttributePoints(oChar,PROPERTY_ATTRIBUTE_STRENGTH, 3,FALSE);
    Chargen_SpendAttributePoints(oChar,PROPERTY_ATTRIBUTE_DEXTERITY, 2,FALSE);

}


// -----------------------------------------------------------------------------
// Core Character
// -----------------------------------------------------------------------------
void main()
{

    event   ev              =   GetCurrentEvent();
    int     nEventType      =   GetEventType (ev);
    object  oChar           =   GetEventObject(ev,0);

    int nMode;
    int nInt0 = GetEventInteger(ev,0);
    int nInt1 = GetEventInteger(ev,1);

    // -------------------------------------------------------------------------
    // Debug Data.
    // -------------------------------------------------------------------------
    Log_Trace(LOG_CHANNEL_EVENTS_CHARGEN,"sys_chargen","Chargen Event:" + Log_GetEventNameById (nEventType) + " " + ToString(nInt0) + "," + ToString(nInt1), oChar);
    TrackModuleEvent(nEventType,GetModule(), oChar,GetEventInteger(ev,0), GetEventInteger(ev,1));

    switch (nEventType)
    {

        // ---------------------------------------------------------------------
        // Fires every time the player requests to enter the levelup screen
        // and causes the Chargen UI to show up.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_PLAYERLEVELUP:
        {
            object oPlayer = GetEventObject(ev,0);

            if (!IsShapeShifted(oPlayer) && (GetGameMode() == GM_EXPLORE || GetGameMode() == GM_GUI))
            {
                StartCharGen(oPlayer,1 /* MODE_LEVELUP */);
            }
            else
            {
                UI_DisplayMessage(oPlayer, UI_MESSAGE_CANT_DO_IN_COMBAT);

            }
            break;
        }

        // ---------------------------------------------------------------------
        // Fired whenever the chargen was invoked, either by starting a new
        // game or by invoking the StartChargen commmand.
        // ---------------------------------------------------------------------
        case EVENT_TYPE_CHARGEN_START:
        {

            // -----------------------------------------------------------------
            // Retrieve and cache the mode in which chargen was started, either
            // CREATE or LEVELIP
            // -----------------------------------------------------------------
            nMode = GetEventInteger(ev,0);
            SetLocalInt(GetModule(),CHARGEN_MODE, nMode);

            if (nMode == CHARGEN_MODE_CREATE)
            {
                // -------------------------------------------------------------
                // This blanks out the character completely, resetting all stats,
                // abilities, etc.
                // -------------------------------------------------------------
                Chargen_InitializeCharacter(oChar,TRUE);
                Log_Chargen("sys_chargen.EVENT_TYPE_CHARGEN_START","Chargen Mode : Create", oChar);
            }
            else
            {
                Log_Chargen("sys_chargen.EVENT_TYPE_CHARGEN_START","Chargen Mode : Levelup", oChar);
            }

            break;
        }

        // ---------------------------------------------------------------------
        // This fires whenever the player selects a soundset for the main hero
        // resource(0) is the conversation file used with the setsoundet command
        // ---------------------------------------------------------------------
        case EVENT_TYPE_CHARGEN_SELECT_SOUNDSET:
        {
            // -----------------------------------------------------------------
            // Playing it safe here, in case someone debug invokes this on top
            // of existing followers.
            // -----------------------------------------------------------------
            if (IsHero(oChar))
            {
                string r = GetEventString(ev, 0);
                SetSoundSet(oChar,r);
            }

            break;
        }


       // ----------------------------------------------------------------------
       // This fires whenever the gender selection on the create a character
       // screen is modified. It also fires when the screen is entered the
       // first time, defaulting the character to male.
       // ----------------------------------------------------------------------
       case EVENT_TYPE_CHARGEN_SELECT_GENDER:
       {
            int nGender   = GetEventInteger(ev,0);
            Chargen_SelectGender(oChar,nGender);
            break;
       }

       // ----------------------------------------------------------------------
       // This fires when the player selects the icon corresponding to any of
       // the available races.
       //
       // int(0) - Constant RACE_* integer
       // int(1) - 1= race selected, 0=race unselected      (unused)
       // ----------------------------------------------------------------------
       case EVENT_TYPE_CHARGEN_SELECT_RACE:
       {
            int nRace    = GetEventInteger(ev,0);
            int bSelected =  GetEventInteger(ev,1);

            // -----------------------------------------------------------------
            // Here we rebuild the character from scratch, reinitializing
            // all values and applying all choices from selections higher
            // on the UI. This avoids having to undo any kind of selections.
            // -----------------------------------------------------------------
            Chargen_InitializeCharacter(oChar,TRUE);
            Chargen_SelectGender(oChar,GetCreatureGender(oChar));
            Chargen_SelectRace(oChar,nRace);

            // -----------------------------------------------------------------
            // Initialize to an invalid class id which InitInventory will handle
            // to load basic gear that's safe for any race/class
            // -----------------------------------------------------------------
            Chargen_InitInventory(oChar,0,0);

            break;
       }


        // ----------------------------------------------------------------------
       // This fires when the player selects the icon corresponding to any of
       // the available classes
       //
       // int(0) - Constant CLASS_* integer
       // int(1) - 1= class selected, 0 = class unselected
       // ----------------------------------------------------------------------
       case EVENT_TYPE_CHARGEN_SELECT_CLASS:
       {
             int nClass    = GetEventInteger(ev,0);
             int bSelected =  GetEventInteger(ev,1);

             // ----------------------------------------------------------------
             // Safety check for classes. This avoids issues with some older,
             // pre ship build exports.
             // ----------------------------------------------------------------
             if (nClass <(MAX_CLASS_INDEX+1) && nClass>0)
             {

                 // ------------------------------------------------------------
                 // If the player had a class selection before, we first need to
                 // rebuild the character.
                 // ------------------------------------------------------------
                 if (!bSelected)
                 {
                     Chargen_InitializeCharacter(oChar,TRUE);
                     Chargen_SelectGender(oChar,GetCreatureGender(oChar));
                     Chargen_SelectRace(oChar,GetCreatureRacialType(oChar));
                 }
                 else
                 {
                     // --------------------------------------------------------
                     // Now set the new class and initialize the inventory
                     // from the class template.
                     // --------------------------------------------------------
                     Chargen_SelectCoreClass(oChar,nClass);
                     Chargen_InitInventory(oChar,nClass,0);
                 }
             }
            break;
       }



       // ----------------------------------------------------------------------
       // This fires when the player selects the icon corresponding to any of
       // the available backgrounds
       //
       // int(0) - Constant BACKGROUND_* integer
       // ----------------------------------------------------------------------
       case EVENT_TYPE_CHARGEN_SELECT_BACKGROUND:
       {
            int nBG       =  GetEventInteger(ev,0);

            // -----------------------------------------------------------------
            // Set the background on the player and reinitialize plot flags
            // for the background
            // -----------------------------------------------------------------
            Chargen_InitializeCharacter(oChar,TRUE);
            Chargen_SelectGender(oChar,GetCreatureGender(oChar));
            Chargen_SelectRace(oChar,GetCreatureRacialType(oChar));
            Chargen_SelectCoreClass(oChar,GetCreatureCoreClass(oChar));


            Chargen_SelectBackground(oChar,nBG, FALSE);
            Chargen_SetupPlotFlags(oChar);


            // -----------------------------------------------------------------
            // Generate the index into the equipment template 2da and
            // then load the starting equipment based on the data returned.
            // -----------------------------------------------------------------
            int nClass = GetCreatureCoreClass(oChar);
            int nRace = GetCreatureRacialType(oChar);
            int nEquipIdx = Chargen_GetEquipIndex(nRace, nClass, nBG);
            Chargen_InitInventory(oChar,0,nEquipIdx);


            break;
       }


        // ---------------------------------------------------------------------
        // This fires whenever the player presses + or - on an attribute to spend
        // points on the attribute screen of character generation
        //
        // int(0) - Constant PROPERTY_* integer
        // int(1) - # of points spent
        // ---------------------------------------------------------------------
/*        case EVENT_TYPE_CHARGEN_ASSIGN_ATTRIBUTES:
        {
            int nAttribute = GetEventInteger(ev,0);
            int nPoints    = GetEventInteger(ev,1);

            // -----------------------------------------------------------------
            // Subtract from available points to spend
            // -----------------------------------------------------------------
            Chargen_ModifyCreaturePropertyBase(oChar, PROPERTY_SIMPLE_ATTRIBUTE_POINTS, IntToFloat(nPoints*-1));


            // -----------------------------------------------------------------
            // Spend it.
            // -----------------------------------------------------------------
            Chargen_SpendAttributePoints(oChar,nAttribute,nPoints,FALSE);
            break;
        }
*/

        // ---------------------------------------------------------------------
        // This fires whenever the player assings an ability
        // (skill/talent/spell/specialization)
        //
        // int(0) - ABILITY_* constant integer. If <0 the ability is removed not added
        // int(1) - If 1, we're dealing with a specialization, if 0 any other ability.
        // ---------------------------------------------------------------------

        case EVENT_TYPE_CHARGEN_ASSIGN_ABILITIES:
        {
            int nAbiNo          = GetEventInteger(ev,0);
            int bSpecialization = (GetEventInteger(ev,1) == 0);
            int nAbi            = abs(nAbiNo);

            // -----------------------------------------------------------------
            // Skill / Talent / Spell
            // -----------------------------------------------------------------
            if (bSpecialization)
            {
                int nType = PROPERTY_SIMPLE_TALENT_POINTS;

                if (GetAbilityType(nAbi) == ABILITY_TYPE_SKILL)
                {
                    nType = PROPERTY_SIMPLE_SKILL_POINTS;
                }
                if (nAbiNo > 0)
                {
                    if (!HasAbility(oChar,nAbiNo))
                    {
                        Chargen_ModifyCreaturePropertyBase(oChar, nType, -1.0f);
                    }
                }
                else
                {
                    if (HasAbility(oChar, abs(nAbiNo)))
                    {
                        Chargen_ModifyCreaturePropertyBase(oChar, nType, 1.0f);
                    }
                }
            }
            // -----------------------------------------------------------------
            // Specialization
            // -----------------------------------------------------------------
            else
            {
                 if (nAbiNo >0)
                 {
                     Chargen_ModifyCreaturePropertyBase(oChar, 38, -1.0f);
                 }
                 else
                 {
                    Chargen_ModifyCreaturePropertyBase(oChar, 38, 1.0f);
                 }
            }

            // -----------------------------------------------------------------
            // This actually adds / removes the ability.
            // -----------------------------------------------------------------
            _AddAbility(oChar,nAbiNo, nAbiNo < 0);

            Log_Trace(LOG_CHANNEL_CHARACTER,"sys_chargen","Assign Ability: " + ToString(nAbiNo), oChar);

            break;
        }

          case EVENT_TYPE_CHARGEN_SELECT_NAME:
          {
            string sName= GetEventString(ev,0);
            SetName(oChar,sName);
            break;
          }

          case EVENT_TYPE_CHARGEN_AUTOLEVEL:
          {

            AL_DoAutoLevelUp(oChar);
            Chargen_SetNumTactics(oChar);
            SetCanLevelUp(oChar,Chargen_HasPointsToSpend(oChar));
              break;
          }


          case EVENT_TYPE_CHARGEN_END:
        {
            nMode = GetEventInteger(ev, 0);            //GetLocalInt(GetModule(),CHARGEN_MODE);
            int nQuickStart = GetEventInteger(ev,1);
            // 0 - quickstart
            // 1 - normal    \
            // 2 - advanced  / treat as the same
            Log_Trace(LOG_CHANNEL_CHARACTER,"sys_chargen","MODE: " + IntToString(nMode) + ", Quick Start: " + IntToString(nQuickStart));


            // -----------------------------------------------------------------
            // Character Creation
            // -----------------------------------------------------------------
            if (nMode == CHARGEN_MODE_CREATE)
            {
                SetMaxInventorySize(INVENTORY_SIZE_BASE, oChar);
                Chargen_EnableTacticsPresets(oChar);

                // add recipes
                CreateItemOnObject(HERBALISM_STARTING_RECIPE1, oChar, 1, "", TRUE);
                CreateItemOnObject(HERBALISM_STARTING_RECIPE2, oChar, 1, "", TRUE);
                CreateItemOnObject(HERBALISM_STARTING_RECIPE3, oChar, 1, "", TRUE);
                CreateItemOnObject(POISON_MAKING_STARTING_RECIPE1, oChar, 1, "", TRUE);
                CreateItemOnObject(POISON_MAKING_STARTING_RECIPE2, oChar, 1, "", TRUE);
                CreateItemOnObject(TRAP_MAKING_STARTING_RECIPE1, oChar, 1, "", TRUE);
                CreateItemOnObject(TRAP_MAKING_STARTING_RECIPE2, oChar, 1, "", TRUE);
                CreateItemOnObject(TRAP_MAKING_STARTING_RECIPE3, oChar, 1, "", TRUE);
                CreateItemOnObject(TRAP_MAKING_STARTING_RECIPE4, oChar, 1, "", TRUE);

                if (IsUsingEP1Resources() == TRUE)
                {
                    CreateItemOnObject(RUNE_MAKING_STARTING_RECIPE1, oChar, 1, "", TRUE);
                    CreateItemOnObject(RUNE_MAKING_STARTING_RECIPE2, oChar, 1, "", TRUE);
                    CreateItemOnObject(RUNE_MAKING_STARTING_RECIPE3, oChar, 1, "", TRUE);
                    CreateItemOnObject(RUNE_MAKING_STARTING_RECIPE4, oChar, 1, "", TRUE);
                }

                // special handling for aluvian
                if (nQuickStart == 0 )
                {
                    Log_Trace(LOG_CHANNEL_CHARACTER,"sys_chargen","Setting default values for player character");

                    int nRandClass = abs((GetLowResTimer()%3)+1);

                    if(nRandClass == CLASS_ROGUE || nRandClass == CLASS_WARRIOR)
                    {
                        _RunChargen(RACE_HUMAN, nRandClass, oChar, BACKGROUND_NOBLE );
                        WR_SetPlotFlag(PLT_GEN00PT_BACKGROUNDS, GEN_BACK_HUMAN_NOBLE, TRUE);
                    }
                    else // mage
                    {
                        _RunChargen(RACE_HUMAN, nRandClass, oChar, BACKGROUND_MAGI );
                        WR_SetPlotFlag(PLT_GEN00PT_BACKGROUNDS, GEN_BACK_CIRCLE, TRUE);
                    }


                    Chargen_SetNumTactics(oChar);
                    SetCanLevelUp(oChar,Chargen_HasPointsToSpend(oChar));

                    SendEventModuleChargenDone("", "");

                }
                else
                {

                    if (nQuickStart == 1)
                    {
                        AL_DoAutoLevelUp(oChar, TRUE, TRUE);
                    }
                    Chargen_SetNumTactics(oChar);
                    SetCanLevelUp(oChar,Chargen_HasPointsToSpend(oChar));
                    if(nQuickStart == 1 || nQuickStart == 2)
                    {
                        SendEventModuleChargenDone("", "");
                    }
                    else if(nQuickStart == 3)
                    {
                        SendEventModuleChargenDone(LEVEL_OF_THE_WEEK_RESREF, LEVEL_OF_THE_WEEK_WAYPOINT);
                    }
                }

                // associate some tactics preset table
                int nPresetTable;
                if(GetCreatureCoreClass(oChar) == CLASS_WARRIOR)
                    nPresetTable = 1; // tank
                else if(GetCreatureCoreClass(oChar) == CLASS_ROGUE)
                    nPresetTable = 2; // damage dealer
                else // mage
                    nPresetTable = 5; // nuker

                //Chargen_LoadPresetsTable(oChar, nPresetTable);
                SetTacticPresetID(oChar, nPresetTable);
            }
            else
            {
                Chargen_SetNumTactics(oChar);
                Chargen_EnableTacticsPresets(oChar);
                Chargen_PopulateTacticsForPreset(oChar);
                SetCanLevelUp(oChar,Chargen_HasPointsToSpend(oChar));
                // Run logic to grant any achievement ability or class related after committing levelup changes
                ACH_WhenHeroLevelsUp(oChar, FALSE);
                ACH_WhenHeroGainsLevel(oChar, FALSE);

                // faster resources regen when higher level
                SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_HEALTH,
                    REGENERATION_HEALTH_EXPLORE_DEFAULT + IntToFloat(GetLevel(oChar)) * 2.0,
                    PROPERTY_VALUE_BASE);
                SetCreatureProperty(oChar, PROPERTY_ATTRIBUTE_REGENERATION_STAMINA,
                    REGENERATION_STAMINA_EXPLORE_DEFAULT+ IntToFloat(GetLevel(oChar)) * 2.0,
                    PROPERTY_VALUE_BASE);

            }
            break;
        }

    }
}